package jbeh;

import java.util.Arrays;
import java.util.List;

import org.jbehave.core.Embeddable;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.embedder.Embedder;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.reporters.StoryReporterBuilder.Format;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.SilentStepMonitor;
import org.jbehave.web.selenium.ContextView;
import org.jbehave.web.selenium.LocalFrameContextView;
import org.jbehave.web.selenium.PerStoriesWebDriverSteps;
import org.jbehave.web.selenium.PropertyWebDriverProvider;
import org.jbehave.web.selenium.SeleniumConfiguration;
import org.jbehave.web.selenium.SeleniumContext;
import org.jbehave.web.selenium.SeleniumStepMonitor;
import org.jbehave.web.selenium.WebDriverProvider;
import org.jbehave.web.selenium.WebDriverScreenshotOnFailure;
import org.jbehave.web.selenium.WebDriverSteps;
import org.jbehave.core.steps.InstanceStepsFactory;

import static org.jbehave.core.io.CodeLocations.*;

import com.google.common.util.concurrent.MoreExecutors;

public class Stories extends JUnitStories {

	private WebDriverProvider driverProvider = new PropertyWebDriverProvider();
	private WebDriverSteps lifecycleSteps = new PerStoriesWebDriverSteps(
			driverProvider); // or PerStoryWebDriverSteps(driverProvider)
	private BahnStartPage pages = new BahnStartPage(driverProvider);
	private SeleniumContext context = new SeleniumContext();
	private ContextView contextView = new LocalFrameContextView().sized(500,
			100);

	public Stories() {
		// If configuring lifecycle per-stories, you need to ensure that you a
		// same-thread executor
		if (lifecycleSteps instanceof PerStoriesWebDriverSteps) {
			configuredEmbedder().useExecutorService(
					MoreExecutors.sameThreadExecutor());
		}
	}

	@Override
	public Configuration configuration() {
		Class<? extends Embeddable> embeddableClass = this.getClass();
		return new SeleniumConfiguration()
				.useSeleniumContext(context)
				.useWebDriverProvider(driverProvider)
				.useStepMonitor(
						new SeleniumStepMonitor(contextView, context,
								new SilentStepMonitor()))
				.useStoryLoader(new LoadFromClasspath(embeddableClass))
				.useStoryReporterBuilder(
						new StoryReporterBuilder()
								.withCodeLocation(
										codeLocationFromClass(embeddableClass))
								.withDefaultFormats()
								.withFormats(Format.CONSOLE, Format.TXT,
										Format.HTML, Format.XML));
	}

	@Override
	public InjectableStepsFactory stepsFactory() {
		Configuration configuration = configuration();
		return new InstanceStepsFactory(configuration, new BahnStartPage(
				driverProvider), lifecycleSteps,
				new WebDriverScreenshotOnFailure(driverProvider, configuration
						.storyReporterBuilder()));
	}

	@Override
	protected List<String> storyPaths() {
		return new StoryFinder().findPaths(
				codeLocationFromClass(this.getClass()).getFile(),
				Arrays.asList("**/*.story"), Arrays.asList(new String[] {}));
	}

	// This Embedder is used by Maven or Ant and it will override anything set
	// in the constructor
	public static class SameThreadEmbedder extends Embedder {

		public SameThreadEmbedder() {
			useExecutorService(MoreExecutors.sameThreadExecutor());
		}

	}

}